#include "Common.h"
#include "SceneNode.h"
#include "MovableObject.h"
#include "Scene.h"
#include <d3dx9.h>

SceneNode::SceneNode(const std::string& name, Scene* owner)
	: mName(name)
	, mOwner(owner)
	, mNeedUpdate(false)
	, mPosition(Vector3::Zero)
	, mScale(Vector3::One)
	, mRotation(Rotator::Identity)
	, mCachedMatrix(Matrix::Identity)
{
	
}

SceneNode::~SceneNode(void)
{
	if (mNeedUpdate)
		mOwner->RemovePendingUpdate(this);
	DettachAll();
}

void SceneNode::Attach(MovableObject* obj)
{
	if (mObjectList.find(obj->getName()) != mObjectList.end())
		return;

	mObjectList[obj->getName()] = obj;
	obj->NotifyAttached(this);

	NeedUpdate();
}

void SceneNode::Dettach(MovableObject* obj)
{
	ObjectList::iterator it = mObjectList.find(obj->getName());
	if (it == mObjectList.end())
		return;

	mObjectList.erase(it);
	obj->NotifyAttached(NULL);

	NeedUpdate();
}

void SceneNode::DettachAll()
{
	for (ObjectList::iterator it(mObjectList.begin()), end(mObjectList.end()); it != end; it++)
		it->second->NotifyAttached(NULL);
	mObjectList.clear();
}

void SceneNode::NeedUpdate()
{
	if (mNeedUpdate)
		return;
	mOwner->PendingUpdate(this);
	mNeedUpdate = true;
}

void SceneNode::Update(float elapsedTime)
{
	if (mNeedUpdate == false)
		return;

	UpdateImpl();

	mNeedUpdate = false;
}

void SceneNode::UpdateImpl()
{
	mCachedMatrix = Matrix::ScaleRotationTranslationMatrix(mScale, mRotation, mPosition);

	for (ObjectList::iterator it(mObjectList.begin()), end(mObjectList.end()); it != end; it++)
		it->second->UpdateTransform();

	UpdateBounds();
}

void SceneNode::UpdateBounds()
{
	mAABB.Init();

	for (ObjectList::iterator it(mObjectList.begin()), end(mObjectList.end()); it != end; it++)
		mAABB.Merge(it->second->getWorldAABB());
}
